觀看本篇前,建議先了解何謂 MVC 模式,簡單說控制器的作用就像是交通警察,應用程式在接收 HTTP 請求後,負責將正確的資料從資料庫或其他儲存機制取出並回傳給使用者,回傳的內容可以是一個 view 檔案或一則簡單的訊息端看開發者如何定義,還有就是不建議將應用程式的所有邏輯處理都寫進控制器 ,比較好的作法是讓控制器只負責解析來自 HTTP 請求的意圖,並引導應用程式的其餘部分去處理這些邏輯。
Laravel 的控制器檔案都放在 app/Http/Controllers 目錄中,並且 artisan 也提供方便的語法來新增:
$ php artisan make:controller DemoController
上述語法會產生一名稱為 DemoController.php 的檔案如下,筆者在這邊自行定義了一個簡單的方法 index:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class DemoController extends Controller
{
public function index()
{
return 'Hello, World !!';
}
}
接著如同上一篇的做法,我們將此控制器掛上一個路由:
<?php
use Illuminate\Support\Facades\Route;
Route::get('/index', 'App\Http\Controllers\DemoController@index');
最後造訪「/index」即可看到 Hello, World !! 訊息。
若你撰寫的控制器只打算匹配一個路由,你可以不用為了替方法想名稱而煩惱,只需將你的方法命名為 __invoke:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class DemoController extends Controller
{
public function __invoke()
{
return 'Hello, World !!';
}
}
這時路由定義可以不標註方法的名稱,Laravel 會將整個類別當做函式呼叫:
<?php
use Illuminate\Support\Facades\Route;
Route::get('/index', 'App\Http\Controllers\DemoController');
除了在路由中使用中介層外,控制器也可以在建構式中使用中介層以及套用在指定的方法上:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class DemoController extends Controller
{
public function __construct()
{
$this->middleware('auth');
$this->middleware('log')->only('index');
$this->middleware('subscribed')->except('store');
}
}
當你為了一項「資源」的 CRUD 處理而撰寫控制器時,Laravel 提供一個很好的方法讓你一次綁定整個資源,這邊以資源「照片」做為示範:
$ php artisan make:controller PhotoController --resource
這時我們會發現檔案內已經預先定義好幾個方法:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class PhotoController extends Controller
{
public function index()
{
//
}
public function create()
{
//
}
public function store(Request $request)
{
//
}
public function show($id)
{
//
}
public function edit($id)
{
//
}
public function update(Request $request, $id)
{
//
}
public function destroy($id)
{
//
}
}
接著我們定義一個路由來指向 PhotoController 這個控制器:
<?php
use Illuminate\Support\Facades\Route;
Route::resource('/photos', 'App\Http\Controllers\PhotoController');
最後我們輸入以下 artisan 指令列出可用路由的清單:
$ php artisan route:list
可以發現有 7 組 Laravel 幫我們設定好的路由完整匹配 PhotoController 控制器內的 7 個方法,這樣便可以省下命名與重複定義路由的功夫。
有需要的話,還可以指定要執行的路由,而不是默認值的全部:
<?php
use Illuminate\Support\Facades\Route;
/* 只會執行匹配控制器中 index、show 兩個方法的路由 */
Route::resource('photos', 'App\Http\Controllers\PhotoController')->only([
'index', 'show'
]);
/* index、show 兩個方法的路由不執行,其他的都會執行 */
Route::resource('photos', 'App\Http\Controllers\PhotoController')->except([
'index', 'show'
]);
在為你的 API 定義資源控制器所匹配的路由時,可以使用 apiResource() 來排除 create、edit 這兩組路由:
<?php
use Illuminate\Support\Facades\Route;
Route::apiResource('photos', 'App\Http\Controllers\PhotoController');
可以透過將陣列傳遞給 apiResource() 達到一次定義多組資源控制器:
<?php
use Illuminate\Support\Facades\Route;
Route::apiResources([
'photos' => 'App\Http\Controllers\PhotoController',
'resources' => 'App\Http\Controllers\ResourceController',
]);
而要快速新增排除 create、edit 方法的 API 資源控制器時,artisan 也有提供方便的指令:
php artisan make:controller PhotoController --api